Skip to content

fix(tdx): parse the nested QE certification data; validate on real hardware - #61

Merged
imran-siddique merged 2 commits into
mainfrom
fix/tdx-nested-qe-certification-data
Jul 27, 2026
Merged

fix(tdx): parse the nested QE certification data; validate on real hardware#61
imran-siddique merged 2 commits into
mainfrom
fix/tdx-nested-qe-certification-data

Conversation

@imran-siddique

Copy link
Copy Markdown
Contributor

What

TdxQuote.parse threw on every genuine DCAP v4 quote.

Real quotes nest the Quoting Enclave material: the bytes after the attestation key are a certification-data header of type 6 (QE_REPORT_CERTIFICATION_DATA) wrapping the QE report, its PCK signature, the auth data and the type-5 PCK chain. The parser read the QE report directly after the attestation key, six bytes early, so a real GCP C3 quote failed on a bogus cert-length read.

The synthetic fixture emitted the same flat layout, so the tests validated the defect. Failure was closed, so this is a false negative rather than an unsound accept, but the TDX path had never worked against real evidence. The same defect is fixed in cmcp (agentrust-io/cmcp#420); agent-manifest, whose parser was written against this exact capture, was already correct.

Now validated against real hardware evidence

Platform Evidence Result
AMD SEV-SNP Azure DCasv5 CVM report + VCEK + AMD ASK/ARK chain Verified: chain to ARK-Milan, ECDSA-P384 report signature, measurement binding; fails closed on a flipped bit
Intel TDX GCP C3 DCAP v4 quote, non-paravisor Verified: quote signature, QE binding, PCK signature, chain to the Intel SGX Root CA, MRTD binding

Env-gated (CA2A_SNP_FIXTURE_DIR, CA2A_TDX_QUOTE) because the captures embed per-CPU identifiers and cannot be committed.

What this does not claim

docs/hardware-validation.md is as explicit about the gap as about the win: this validates the verifier against real evidence, not a running attested peer. The live handshake still runs in software mode at assurance="none", so cA2A is still not attested across trust domains, and that stays on the ROADMAP critical path. TPM remains synthetic-only.

Test plan

  • pytest tests/unit/test_tdx.py with CA2A_TDX_QUOTE — 11 passed
  • pytest tests/unit/test_sev_snp.py with CA2A_SNP_FIXTURE_DIR — 11 passed
  • pytest tests/ — 198 passed, 6 pre-existing test_cedar.py failures unrelated to this change (they fail identically on a clean tree; local cedar binding issue)

🤖 Generated with Claude Code

imran-siddique and others added 2 commits July 21, 2026 16:51
Removes ca2a's last duplicated attestation crypto. ca2a_verify.verify_cert_chain
(shared by the SEV-SNP VCEK, TDX PCK, and TPM AK chains) now delegates to
agent_manifest.verify_cert_chain, the org's shared generic algorithm-agnostic
verifier, re-raising CertChainError as AttestationFailed to preserve ca2a's
contract. ca2a keeps its own parsers, per-format signature checks, appraisal
shapes, trust-root pinning, and verify_offer semantics.

Dep: adds agent-manifest>=0.5. 201 tests pass unchanged; ruff + mypy clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rdware

TdxQuote.parse threw on every genuine DCAP v4 quote. Real quotes nest the
Quoting Enclave material: the bytes after the attestation key are a
certification-data header of type 6 (QE_REPORT_CERTIFICATION_DATA) wrapping the
QE report, its PCK signature, the auth data and the type-5 PCK chain. The parser
read the QE report directly after the attestation key, six bytes early, so a real
GCP C3 quote failed with a bogus cert-length read.

The synthetic fixture emitted the same flat layout, so the tests validated the
defect. Failure was closed, so this is a false negative rather than an unsound
accept, but the TDX path had never worked against real evidence.

Both verifiers now run against genuine hardware evidence, env-gated because the
captures embed per-CPU identifiers: a real Azure CVM SEV-SNP report
(CA2A_SNP_FIXTURE_DIR) and a real GCP C3 TDX quote (CA2A_TDX_QUOTE), each also
asserted to fail closed on a tampered copy.

docs/hardware-validation.md records what is now verified and, as importantly,
what still is not: this validates the verifier, not a running attested peer. The
live handshake is still software mode, so cA2A is still not attested across trust
domains, and LIMITATIONS and ROADMAP say so.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@imran-siddique
imran-siddique merged commit 82be440 into main Jul 27, 2026
12 checks passed
imran-siddique added a commit that referenced this pull request Jul 28, 2026
…SNP to GCP TDX) (#68)

* test(tpm): validate the TPM verifier against a real Azure vTPM quote

Captured a genuine TPM 2.0 quote from an Azure Trusted Launch VM (vTPM, secure
boot, PCRs 0-7 under a fresh nonce). The verifier's parse, magic and type
checks, qualifying-data binding, PCR digest and AK RSA PKCS#1 v1.5 SHA-256
signature all hold on it, and a flipped bit in the attest blob is rejected.
Env-gated on CA2A_TPM_FIXTURE_DIR; the capture is not committed.

What this does not close, stated in docs/hardware-validation.md rather than
glossed: the AK certificate chain. Azure's pre-provisioned AK certificate
certifies a different key than an in-guest tpm2_createak AK, so it does not
verify against this quote, and it carries no AIA extension, so its issuing
intermediate is not fetchable from it. Chain-to-vendor-root stays unexercised
for TPM, which is why this verifier takes caller-supplied roots rather than
pinning one. This is also a Hyper-V vTPM, not a discrete TPM chip.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs: the attestation seam ran off a real SEV-SNP quote; assurance=hardware

Drove ca2a_runtime.attestation's verifier seam off a live SEV-SNP quote on an
Azure DC2ads_v5 confidential VM. verify_offer returned assurance="hardware"
rather than "none" for the first time, a payload was sealed to a channel key a
hardware-verified measurement vouches for and opened inside the enclave, and
both a measurement mismatch and a stale nonce were rejected.

Azure SEV-SNP is paravisor-mediated, so the binding is one hop longer than
bare-metal: the caller's nonce rides in the AK-signed TPM quote, the paravisor
binds that AK into the SNP report's REPORT_DATA, and the report chains VCEK to
ASK to ARK-Milan against AMD KDS. docs/hardware-validation.md spells that out.

What this does not close is said in the same breath, in LIMITATIONS and the
ROADMAP: the run had one attested peer with the caller on the same host, so cA2A
is still not demonstrated attested across trust domains. That needs two
independently operated attested peers. Software mode also remains the default
for the reference transport; the hardware path is a validated capability, not
the shipped default.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs: record the cross-operator, cross-TEE run (Azure SNP to GCP TDX)

An AMD SEV-SNP peer on Azure called an Intel TDX peer on GCP: different clouds,
different operators, unrelated attestation formats. The caller appraised the
callee's genuine 8KB TDX quote against the pinned Intel SGX Root CA, confirmed
the quote's REPORTDATA bound the callee's channel key under a nonce the caller
chose, and only then sealed a delegated task. The TDX enclave opened it, enforced
a scope narrowed by a chain it did not issue, allowed tool:search, and refused
tool:purchase with a denial record carrying the requested capability, the
effective scope and the reason back across the trust boundary. A stale nonce was
rejected.

That is the four primitives holding at once across a real trust boundary, which
is what the cross-operator claim rested on.

Two honest limits are recorded with it: the attestation was one-directional, so
the callee never appraised the caller, and both peers ran from one operator's
harness. Mutual simultaneous attestation is the remaining step. The committed
cross-operator example stays software-attested, because real evidence embeds
per-CPU identifiers and cannot be shipped as a fixture.

Also carries the two commits orphaned when #61 merged: the real Azure vTPM quote
test and the assurance="hardware" live-peer run.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant